#include "Containers/TokenizedLine.h"
#include "Functions/String.h"
#include "TObjArray.h"
#include "TObjString.h"
using namespace BOSS_Afterburner;

TokenizedLine::TokenizedLine(const TString& input, const char* delim) :
  fDelimiter(delim),
  fDelimWidth(fDelimiter.Length())
{
  SetLineAndTokenize(input);
}

void TokenizedLine::SetLineAndTokenize(const TString& input)
{
  fLine = input;
  InsertSpaces();
  SetArrayOfSegments();
}

void TokenizedLine::InsertSpaces()
{
  fLine.ReplaceAll(fDelimiter, Form(" %s ", GetDelimiter()));
}

void TokenizedLine::SetArrayOfSegments()
{
  fArrayOfSegments.clear();
  auto ptr = fLine.Tokenize(fDelimiter);
  if(!ptr) return;
  TObjArrayIter next(ptr);
  while(auto obj = next())
  {
    auto strObj = dynamic_cast<TObjString*>(obj);
    if(!strObj) return;
    TString str{strObj->GetString()};
    String::Trim(str);
    fArrayOfSegments.push_back(str);
  }
}

const Int_t TokenizedLine::GetNSegments() const
{
  return fArrayOfSegments.size();
}

const TString& TokenizedLine::GetSegment(Int_t i) const
{
  i = FlipIndex(i);
  if(IndexOutOfRange(i) || !fArrayOfSegments.at(i)) return "";
  return fArrayOfSegments.at(i);
}

TString TokenizedLine::BuildMergedSegments(Int_t first, Int_t last) const
{
  first = FlipIndex(first);
  last  = FlipIndex(last);
  if(IndexOutOfRange(first) || IndexOutOfRange(last) || first > last) return "";
  TString output;
  for(Int_t i = first; i <= last; ++i)
  {
    output += GetSegment(i);
    if(i != last) output += Form("%s ", GetDelimiter());
  }
  return output;
}

Int_t TokenizedLine::FlipIndex(Int_t i) const
{
  if(i < 0) i += GetNSegments();
  return i;
}

Bool_t TokenizedLine::IndexOutOfRange(const Int_t& i) const
{
  return i < 0 || i >= GetNSegments();
}